package graph;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.Map;

import solver.Decision;

/**
 * Contains the graph representing the program, in addition to the property node.
 * 
 * @author Habib
 *
 */

public class Graph implements Serializable, Cloneable{
	
	private static final long serialVersionUID = 8015929536367420800L;
	
	/**
	 * The root of the program tree
	 */
	Node root;
	
	/**
	 * The property node
	 */
	Node property;
	
	/**
	 * A collection of variables declared in the program
	 */
	Map<String,VariableNode> declaredVariables;
	
	/**
	 * @param root
	 * @param declaredVariables
	 */
	public Graph(Node root, Map<String, VariableNode> declaredVariables) {
		super();
		this.root = root;
		this.declaredVariables = declaredVariables;
		property = null;
	}
	
	/**
	 * @return the root
	 */
	public Node getRoot() {
		return root;
	}
	
	/**
	 * @param root the root to set
	 */
	public void setRoot(Node root) {
		this.root = root;
	}
	
	/**
	 * @return the property
	 */
	public Node getProperty() {
		return property;
	}
	
	/**
	 * @param property the property to set
	 */
	public void setProperty(Node property) {
		this.property = property;
	}
	
	/**
	 * @return the declaredVariables
	 */
	public Map<String, VariableNode> getDeclaredVariables() {
		return declaredVariables;
	}
	
	/**
	 * @param declaredVariables the declaredVariables to set
	 */
	public void setDeclaredVariables(Map<String, VariableNode> declaredVariables) {
		this.declaredVariables = declaredVariables;
	}
	
	/**
	 * Returns whether the property node has been able to get a value
	 * representing the decision
	 * 
	 * @return the decision: YES, NO or UNKNOWN
	 */
	public Decision isResolved()
	{
		ValueNode valueNode = (ValueNode)property;
		
		if(valueNode.isValidValue())
		{
			BoolValueNode boolValueNode = (BoolValueNode) valueNode;
			if(boolValueNode.getValue() == true)
				return Decision.YES;
			else
				return Decision.NO;
		}
		else
			return Decision.UNKNOWN;
	}
	
	/**
	 * Returns a deep copy of the graph
	 */
	public Graph clone()
	{
		{
			Graph graph_c = null;
			 try {
		            // Write the object out to a byte array
		            ByteArrayOutputStream bos = new ByteArrayOutputStream();
		            ObjectOutputStream out = new ObjectOutputStream(bos);
		            out.writeObject(this);
		            out.flush();
		            out.close();

		            // Make an input stream from the byte array and read
		            // a copy of the object back in.
		            ObjectInputStream in = new ObjectInputStream(
		                new ByteArrayInputStream(bos.toByteArray()));
		            graph_c = (Graph) in.readObject();
		        }
		        catch(IOException e) {
		            e.printStackTrace();
		        }
		        catch(ClassNotFoundException cnfe) {
		            cnfe.printStackTrace();
		        }
		        return graph_c;

		}
	}

	
}
